﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.Ports;
using System.Threading;
using System.Timers;

namespace HirelSeriesH.Tools
{
    /// <summary>
    /// 电表通讯类（型号：DDS4921）
    ///  modbus协议，9600，8，1，even
    ///  读取电压命令：01 04 00 00 00 02 71 CB
    ///  返回：01 04 04 43 6B 58 0E 25 D8 ,其中43 6B 58 0E（4个字节）为电压浮点数，转浮点数为：235.344
    ///  读取电流命令：01 04 00 08 00 02 CRC1 CRC2
    ///  读取有功功率命令：01 04 00 12 00 02 CRC1 CRC2
    /// </summary>
    public class EMcomm
    {
        public SerialPort serial;
        public System.Timers.Timer Timer = new System.Timers.Timer();
        public string Voltage = "0";//电压读数
        public string Current = "0";//电流读数
        public string Power = "0";//有功功率

        public string Voltage2 = "0";//电压读数
        public string Current2 = "0";//电流读数
        public string Power2 = "0";//有功功率

        public string Voltage3 = "0";//电压读数
        public string Current3 = "0";//电流读数
        public string Power3 = "0";//有功功率

        public string EMName = "EM1";//电表名称
        public delegate void RefreshDelegate();
        /*public event RefreshDelegate refreshEM;
        public event RefreshDelegate refreshEMN;*/
        public DateTime NextRecTime = new DateTime();
        public EMcomm(SerialPort sp, string name)
        {
            EMName = name;
            serial = sp;
            Timer.Interval = 1000 * 5;
            Timer.Elapsed += new ElapsedEventHandler(Timer1_Tick);
        }

        private void Timer1_Tick(object sender, ElapsedEventArgs e)
        {
            if (serial == null || !serial.IsOpen)
            {
                return;
            }
            if (EMName == "EM1")
            {
                Voltage = CMDGet(0x00).ToString("f1") + "V";
                Current = CMDGet(0x08).ToString("f1") + "A";
                Power = CMDGet(0x12).ToString("f1") + "W";
                //refreshEM();
                //记录文件
                if (DateTime.Now >= NextRecTime)
                {
                    string sNow = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
                    string msg = sNow + "\t" + Voltage + "\t" + Current + "\t" + Power;
                    Save2File(msg);
                    NextRecTime = DateTime.Now.AddMinutes(1);//每1分钟记录一次 
                }
            }
            else
            {
                //电压
                byte[] commddy = new byte[] { 0X01, 0X04, 0X00, 0X00, 0X00, 0X03 };
                byte[] CMD = CheckWorker.ModbusCRC16(commddy);
                serial.DiscardInBuffer();
                serial.Write(CMD, 0, CMD.Length);

                int bytes = 0;
                for (int i = 0; i < 20; i++)
                {
                    Thread.Sleep(10);
                    bytes = serial.BytesToRead;
                    if (bytes >= 11) break;
                }
                if (bytes != 11)
                {
                    return;
                }
                byte[] tempBuffer = new byte[bytes];
                serial.Read(tempBuffer, 0, bytes);

                byte[] data = new byte[] { 0, 0 };
                for (int i = 3; i < 9; i = i + 2)
                {
                    data[0] = tempBuffer[i];
                    data[1] = tempBuffer[i + 1];

                    if (BitConverter.IsLittleEndian)
                    {
                        Array.Reverse(data);
                    }
                    short V = BitConverter.ToInt16(data, 0);
                    if (i == 3)
                    {
                        Voltage = (float.Parse(V.ToString()) / 10.0f).ToString("0.0") + "V";
                    }
                    if (i == 5)
                    {
                        Voltage2 = (float.Parse(V.ToString()) / 10.0f).ToString("0.0") + "V";
                    }
                    if (i == 7)
                    {
                        Voltage3 = (float.Parse(V.ToString()) / 10.0f).ToString("0.0") + "V";
                    }
                }
                //电流
                byte[] commddl = new byte[] { 0X01, 0X04, 0X00, 0X08, 0X00, 0X03 };
                CMD = CheckWorker.ModbusCRC16(commddl);
                serial.DiscardInBuffer();
                serial.Write(CMD, 0, CMD.Length);

                bytes = 0;
                for (int i = 0; i < 20; i++)
                {
                    Thread.Sleep(10);
                    bytes = serial.BytesToRead;
                    if (bytes >= 11) break;
                }
                if (bytes != 11)
                {
                    return;
                }
                tempBuffer = new byte[bytes];
                serial.Read(tempBuffer, 0, bytes);

                data = new byte[] { 0, 0 };
                for (int i = 3; i < 9; i = i + 2)
                {
                    data[0] = tempBuffer[i];
                    data[1] = tempBuffer[i + 1];

                    if (BitConverter.IsLittleEndian)
                    {
                        Array.Reverse(data);
                    }
                    short V = BitConverter.ToInt16(data, 0);
                    if (i == 3)
                    {
                        Current = (float.Parse(V.ToString()) / 100.0f).ToString("0.0") + "A";
                    }
                    if (i == 5)
                    {
                        Current2 = (float.Parse(V.ToString()) / 100.0f).ToString("0.0") + "A";
                    }
                    if (i == 7)
                    {
                        Current3 = (float.Parse(V.ToString()) / 100.0f).ToString("0.0") + "A";
                    }
                }
                //功率
                byte[] commdgl = new byte[] { 0X01, 0X04, 0X00, 0X12, 0X00, 0X03 };
                CMD = CheckWorker.ModbusCRC16(commdgl);
                serial.DiscardInBuffer();
                serial.Write(CMD, 0, CMD.Length);

                bytes = 0;
                for (int i = 0; i < 20; i++)
                {
                    Thread.Sleep(10);
                    bytes = serial.BytesToRead;
                    if (bytes >= 11) break;
                }
                if (bytes != 11)
                {
                    return;
                }
                tempBuffer = new byte[bytes];
                serial.Read(tempBuffer, 0, bytes);

                data = new byte[] { 0, 0 };
                for (int i = 3; i < 9; i = i + 2)
                {
                    data[0] = tempBuffer[i];
                    data[1] = tempBuffer[i + 1];

                    if (BitConverter.IsLittleEndian)
                    {
                        Array.Reverse(data);
                    }
                    short V = BitConverter.ToInt16(data, 0);
                    if (i == 3)
                    {
                        Power = float.Parse(V.ToString()).ToString("0.0") + "W";
                    }
                    if (i == 5)
                    {
                        Power2 = float.Parse(V.ToString()).ToString("0.0") + "W";
                    }
                    if (i == 7)
                    {
                        Power3 = float.Parse(V.ToString()).ToString("0.0") + "W";
                    }
                }
                //refreshEMN();

                /*byte[] commddy = new byte[] { 0X01, 0X04, 0X01, 0X90, 0X00, 0X0B };
                byte[] CMD = CheckWorker.ModbusCRC16(commddy);
                serial.DiscardInBuffer();
                serial.Write(CMD, 0, CMD.Length);

                int bytes = 0;
                for (int i = 0; i < 20; i++)
                {
                    Thread.Sleep(10);
                    bytes = serial.BytesToRead;
                    if (bytes >= 27) break;
                }
                if (bytes != 27)
                {
                    return;
                }
                byte[] tempBuffer = new byte[bytes];
                serial.Read(tempBuffer, 0, bytes);

                byte[] data = new byte[] { 0, 0 };
                for (int i = 3; i < 9; i = i + 2)
                {
                    data[0] = tempBuffer[i];
                    data[1] = tempBuffer[i + 1];

                    if (BitConverter.IsLittleEndian)
                    {
                        Array.Reverse(data);
                    }
                    short V = BitConverter.ToInt16(data, 0);
                    if (i == 3)
                    {
                        Voltage = (float.Parse(V.ToString()) / 10.0f).ToString("0.0") + "V";
                    }
                    if (i == 5)
                    {
                        Current = (float.Parse(V.ToString()) / 100.0f).ToString("0.0") + "A";
                    }
                    if (i == 7)
                    {
                        Power = (float.Parse(V.ToString()) / 10.0f).ToString("0.0") + "W";
                    }
                }*/

                //记录文件
                if (DateTime.Now >= NextRecTime)
                {
                    string sNow = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
                    string msg = sNow + "\t" + "#A" + "\t" + Voltage + "\t" + Current + "\t" + Power;
                    Save2File(msg);
                    msg = sNow + "\t" + "#B" + "\t" + Voltage2 + "\t" + Current2 + "\t" + Power2;
                    Save2File(msg);
                    msg = sNow + "\t" + "#C" + "\t" + Voltage3 + "\t" + Current3 + "\t" + Power3;
                    Save2File(msg);
                    NextRecTime = DateTime.Now.AddMinutes(1);//每1分钟记录一次 
                }
            }

        }

        public string[] QueryEM(int address)
        {
            string[] data = new string[10];
            double[] rdata = CDMGet(address);
            if (rdata == null) return null;
            int j = 0;
            for (int i = 0; i < 11; i++)
            {
                if (i == 6) continue;//第7个是空值，无用
                if (i < 3)
                {
                    data[j] = (rdata[i] / 10).ToString("f1");
                }
                else if (i < 6)
                {
                    data[j] = (rdata[i] / 100).ToString("f2");
                }
                else
                {
                    data[j] = rdata[i].ToString("f0");
                }
                j++;
            }

            return data;
        }
        private double[] CDMGet(int address)
        {
            byte[] data;

            //byte adr = (byte)(176 + address);//地址B(176)开头
            byte[] cmd = MakeCMD((byte)address, 0, 0, 0, 0x0B);
            byte[] rps = SendCMD(cmd);

            if (rps == null) return null;
            if (rps.Length != 27 && rps.Length != 7) return null;//返回消息小于7字节则返回false
            if (rps[2] != 0x16 && rps[2] != 0x02) return null;//长度L不等于0x16(22)则返回false

            List<byte> ldata = new List<byte>();
            for (int i = 3; i < 25; i++)//取4-19的16个字节
            {
                ldata.Add(rps[i]);
            }
            data = ldata.ToArray();

            return DataParse(data);
        }
        /// <summary>
        /// 读取电表读数
        /// </summary>
        /// <param name="hexlow">00-电压/08-电流/12-有功功率</param>
        /// <returns></returns>
        public float CMDGet(byte hexlow)
        {
            byte[] data;
            int address = 1;
            byte[] cmd = MakeCMD((byte)address, 0, hexlow, 0, 0x02);
            byte[] rps = SendCMD(cmd);
            if (rps == null) return 0;
            if (rps.Length != 9) return 0;//返回消息小于9字节则返回false
            if (rps[2] != 0x04) return 0;//长度L不等于0x04则返回false

            List<byte> ldata = new List<byte>();
            for (int i = 3; i < 7; i++)//取4-19的16个字节
            {
                ldata.Add(rps[i]);
            }
            data = ldata.ToArray();

            /*string strreault = "";
            foreach (var hex in data)
            {
                strreault += hex.ToString("X2");
            }
            float f = Hex2Float(strreault);*/

            if (BitConverter.IsLittleEndian)
            {
                Array.Reverse(data);
            }
            float f = BitConverter.ToSingle(data, 0);
            return f;
        }
        private double[] DataParse(byte[] data)
        {
            double k1 = 1;//
            double[] ddata = new double[11];
            int x;
            for (int i = 0; i < 11; i++)
            {
                x = data[i * 2] * 256 + data[i * 2 + 1];

                ddata[i] = x * k1;
            }

            return ddata;
        }
        /// <summary>
        /// 通讯命令
        /// </summary>
        /// <param name="bADR">地址：1~2</param>
        /// <param name="hPARM1">命令参数1</param>
        /// <param name="hPARM2">命令参数2</param>
        /// <param name="bPARM1">参数高位</param>
        /// <param name="bPARM2">参数低位（读字节数）</param>
        /// <param name="bCMD">命令：0x04</param>
        /// <returns></returns>
        public byte[] MakeCMD(byte bADR, byte hPARM1, byte hPARM2, byte bPARM1, byte bPARM2, byte bCMD = 0x04)
        {
            byte[] send = new byte[6];
            send[0] = bADR;
            send[1] = bCMD;
            send[2] = hPARM1;
            send[3] = hPARM2;
            send[4] = bPARM1;
            send[5] = bPARM2;

            return CheckWorker.ModbusCRC16(send);
        }
        public byte[] SendCMD(byte[] CMD)
        {
            if (!serial.IsOpen)
            {
                return null;
            }
            try
            {
                serial.DiscardInBuffer();
                serial.Write(CMD, 0, CMD.Length);

                int bytes = 0;
                for (int i = 0; i < 20; i++)
                {
                    Thread.Sleep(10);
                    bytes = serial.BytesToRead;
                    //if (bytes == 7 || bytes == 27) break;
                    if (bytes >= 9) break;
                }
                byte[] tempBuffer = new byte[bytes];
                serial.Read(tempBuffer, 0, bytes);

                return tempBuffer;
            }
            catch (Exception ex)
            {
                Debug.WriteLine("读取电表异常：" + ex.ToString());
                return null;
            }

        }

        private object loker = new object();
        public void Save2File(string msg, string filePrefix = "")
        {
            string FilePathRoot = "D:\\PTC";
            //string logDir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, string.Format(@"EM\{0}\", DateTime.Now.ToString("yyyyMM")));
            string logDir = Path.Combine(FilePathRoot, string.Format(@"EM\{0}\", DateTime.Now.ToString("yyyyMM")));

            if (!Directory.Exists(logDir))
            {
                Directory.CreateDirectory(logDir);
            }
            string fileName = EMName + "_" + DateTime.Now.ToString("yyyy-MM-dd") + ".txt";
            if (!string.IsNullOrEmpty(filePrefix))
                fileName = filePrefix + fileName;
            lock (loker)
            {
                using (StreamWriter sw = new StreamWriter(logDir + fileName, true))
                {
                    //sw.WriteLine(DateTime.Now.ToString() + ":" + msg);
                    sw.WriteLine(msg);
                    sw.WriteLine("======");
                    sw.Close();
                }
            }
        }
        //16进制转浮点类型
        public float Hex2Float(string hexString)
        {
            try
            {
                hexString = hexString.Replace(" ", "");
                uint num = uint.Parse(hexString, System.Globalization.NumberStyles.AllowHexSpecifier);
                byte[] floatVals = BitConverter.GetBytes(num);
                float f = BitConverter.ToSingle(floatVals, 0);

                return f;
            }
            catch (Exception ex)
            {
                Debug.WriteLine("16进制转浮点类型异常：" + ex.ToString());
                return 0;
            }

        }
    }
}
